/*
 * ModeloX.cpp
 *
 *  Created on: 23/06/2012
 *      Author: natuchis
 */

#include "ModeloX.h"

typedef pair <string, Contexto*> ParContexto;

ModeloX::ModeloX() {

	this->mapaCtx = new map <string, Contexto*>;
}


ModeloX::~ModeloX() {

	for (this->itMapaCtx = this->mapaCtx->begin(); this->itMapaCtx != this->mapaCtx->end(); this->itMapaCtx++) {
		delete this->itMapaCtx->second;
	}
	delete this->mapaCtx;
}


void ModeloX::actualizar(string contexto, char carac) {

	if (this->existeContexto(contexto)) {
		this->mapaCtx->find(contexto)->second->actualizarContexto(carac);
	}
	else {
		this->agregarContexto(contexto);
	}

	string ctxConCaracActual = contexto + carac;
	ctxConCaracActual.erase(0,1);
	if (!this->existeContexto(ctxConCaracActual)) {
		this->agregarContexto(ctxConCaracActual);
	}
}


void ModeloX::agregarContexto(string contexto) {

	if (!this->existeContexto(contexto)) {
		this->mapaCtx->insert(ParContexto(contexto, new Contexto()));
	}
}


bool ModeloX::existeContexto(string contexto) {

	this->itMapaCtx = this->mapaCtx->find(contexto);
	return (this->itMapaCtx != this->mapaCtx->end());
}

bool ModeloX::existeCaracterEnEsteContexto(string contexto, char carac) {

	this->itMapaCtx = this->mapaCtx->find(contexto);
	if (this->itMapaCtx != this->mapaCtx->end()) {
		return this->itMapaCtx->second->existeCaracter(carac);
	}
	else
		return false;
}


unsigned long int ModeloX::getFrecuenciaTotal(string contexto) {

	unsigned long int frec;
	if (this->existeContexto(contexto)) {
		frec = this->getContexto(contexto)->getFrecuenciaTotal();
	}
	else {
		frec = this->getFrecuenciaEsc(contexto);
	}
	return frec;
}

void ModeloX::setExcluidos(string contexto, set<char> *excluidos) {
	if (existeContexto(contexto)) {
		this->getContexto(contexto)->setExcluidos(excluidos);
	}
}

unsigned long int ModeloX::getCantExcluidosPresentesEnModelo(string contexto, set<char> *excluidos) {

	return this->getContexto(contexto)->getCantExcluidosPresentesEnContexto(excluidos);
}

Contexto* ModeloX::getContexto(string contexto) const{

	return this->mapaCtx->find(contexto)->second;
}

void ModeloX::comprimir(string contexto, char carac, set<char> *excluidos, Datos &datos, bool estoyEnElEof) {

	this->contextoActual = contexto;

	map<string, Caracter> mapa;
	mapa.clear();

	unsigned long int frecEsc;
	if (existeContexto(contexto)) {
		Contexto *ctx = this->getContexto(contexto);

		frecEsc = ctx->getFrecuenciaEsc() - ctx->getCantExcluidosPresentesEnContexto(excluidos);

		// Caso especial, si el contexto tiene un solo caracter y se encuentra excluido.
		if (frecEsc == 0) {
			frecEsc = 1;
		}

		mapa.insert(pair<string,Caracter>("ESC", Caracter(frecEsc)));
		ctx->agregarCaracteresNoExcluidos(mapa, excluidos);

		datos.setCaracteres(mapa);

		datos.setFrecTotal(ctx->getFrecuenciaTotal() - ctx->getFrecuenciaTotalExcluidos(excluidos) + frecEsc);

		if (!estoyEnElEof) {
			if (ctx->existeCaracter(carac)) {
				datos.setCaracAComp(string(1,carac));
			}
			else {
				datos.setCaracAComp("ESC");
			}
		}
		else {
			//Porque se que en un modeloX no lo voy a encontrar.
			datos.setCaracAComp("ESC");
		}

//		map<char,Caracter>::iterator it;
//
//		for (it = mapa.begin(); it != mapa.end(); it++) {
//			cout << "Caracter " << (*it).first << endl;
//			cout << "Frec " << (*it).second.getFrecuencia() << endl;
//		}

	}
	else {

//		cout << " Cuando no existe contexto " << endl;
		frecEsc = this->getFrecuenciaEsc(contexto);
		mapa.insert(pair<string,Caracter>("ESC", Caracter(frecEsc)));

		datos.setCaracteres(mapa);

		datos.setFrecTotal(frecEsc);
		datos.setCaracAComp("ESC");


//		map<char,Caracter>::iterator it;
//
//		for (it = mapa.begin(); it != mapa.end(); it++) {
//			cout << "Caracter " << (*it).first << endl;
//			cout << "Frec " << (*it).second.getFrecuencia() << endl;
//		}

	}
//
//	cout << "Frec Total " << datos.getFrecTotal() << endl;
//
//	cout << "Caracter a comp " << datos.getCaracAComp() << endl;

}


void ModeloX::actualizarModeloYExcluidos(string contexto, char carac, set<char> *excluidos) {

	this->getContexto(contexto)->setExcluidos(excluidos);
	this->actualizar(contexto, carac);
}

void ModeloX::agregarCaracter(char carac) {
}

void ModeloX::getMapa(string contexto, map<string,Caracter> &mapa, set<char> *excluidos) {

	this->getContexto(contexto)->getMapa(mapa, excluidos);
}

unsigned long int ModeloX::getFrecuenciaTotalExcluidos(string contexto, set<char> *excluidos) {
	return this->getContexto(contexto)->getFrecuenciaTotalExcluidos(excluidos);
}

unsigned long int ModeloX::getFrecuenciaEsc(string contexto) {

	return this->getContexto(contexto)->getFrecuenciaEsc();
}
